package com.aplink.generic.util;

import android.util.Log;

import com.google.android.gms.maps.model.LatLng;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.io.InputStream;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

public class MapV2GetRouteDirection {
    public final static String MODE_DRIVING = "driving";
    public final static String MODE_WALKING = "walking";

    public MapV2GetRouteDirection() {
    }

    private ArrayList<LatLng> decodePoly( String encoded ) {
        final ArrayList<LatLng> poly = new ArrayList<LatLng>();
        int index = 0;
        final int len = encoded.length();
        int lat = 0, lng = 0;
        while ( index < len ) {
            int b, shift = 0, result = 0;
            do {
                b = encoded.charAt( index++ ) - 63;
                result |= ( b & 0x1f ) << shift;
                shift += 5;
            } while ( b >= 0x20 );
            final int dlat = ( ( result & 1 ) != 0 ? ~ ( result >> 1 ) : ( result >> 1 ) );
            lat += dlat;
            shift = 0;
            result = 0;
            do {
                b = encoded.charAt( index++ ) - 63;
                result |= ( b & 0x1f ) << shift;
                shift += 5;
            } while ( b >= 0x20 );
            final int dlng = ( ( result & 1 ) != 0 ? ~ ( result >> 1 ) : ( result >> 1 ) );
            lng += dlng;

            final LatLng position = new LatLng( lat / 1E5, lng / 1E5 );
            poly.add( position );
        }
        return poly;
    }

    private int getNodeIndex( NodeList nl, String nodename ) {
        for ( int i = 0 ; i < nl.getLength() ; i++ ) {
            if ( nl.item( i ).getNodeName().equals( nodename ) ) {
                return i;
            }
        }
        return - 1;
    }

    public String getCopyRights( Document doc ) {
        final NodeList nl1 = doc.getElementsByTagName( "copyrights" );
        final Node node1 = nl1.item( 0 );
        Log.i( "CopyRights", node1.getTextContent() );
        return node1.getTextContent();
    }

    public ArrayList<LatLng> getDirection( Document doc ) {
        NodeList nl1, nl2, nl3;
        final ArrayList<LatLng> listGeopoints = new ArrayList<LatLng>();
        nl1 = doc.getElementsByTagName( "step" );
        if ( nl1.getLength() > 0 ) {
            for ( int i = 0 ; i < nl1.getLength() ; i++ ) {
                final Node node1 = nl1.item( i );
                nl2 = node1.getChildNodes();

                Node locationNode = nl2
                        .item( this.getNodeIndex( nl2, "start_location" ) );
                nl3 = locationNode.getChildNodes();
                Node latNode = nl3.item( this.getNodeIndex( nl3, "lat" ) );
                double lat = Double.parseDouble( latNode.getTextContent() );
                Node lngNode = nl3.item( this.getNodeIndex( nl3, "lng" ) );
                double lng = Double.parseDouble( lngNode.getTextContent() );
                listGeopoints.add( new LatLng( lat, lng ) );

                locationNode = nl2.item( this.getNodeIndex( nl2, "polyline" ) );
                nl3 = locationNode.getChildNodes();
                latNode = nl3.item( this.getNodeIndex( nl3, "points" ) );
                final ArrayList<LatLng> arr = this.decodePoly( latNode.getTextContent() );
                for ( int j = 0 ; j < arr.size() ; j++ ) {
                    listGeopoints.add( new LatLng( arr.get( j ).latitude, arr
                            .get( j ).longitude ) );
                }

                locationNode = nl2.item( this.getNodeIndex( nl2, "end_location" ) );
                nl3 = locationNode.getChildNodes();
                latNode = nl3.item( this.getNodeIndex( nl3, "lat" ) );
                lat = Double.parseDouble( latNode.getTextContent() );
                lngNode = nl3.item( this.getNodeIndex( nl3, "lng" ) );
                lng = Double.parseDouble( lngNode.getTextContent() );
                listGeopoints.add( new LatLng( lat, lng ) );
            }
        }

        return listGeopoints;
    }

    public String getDistanceText( Document doc ) {
        final NodeList nl1 = doc.getElementsByTagName( "distance" );
        final Node node1 = nl1.item( 0 );
        final NodeList nl2 = node1.getChildNodes();
        final Node node2 = nl2.item( this.getNodeIndex( nl2, "text" ) );
        Log.i( "DistanceText", node2.getTextContent() );
        return node2.getTextContent();
    }

    public int getDistanceValue( Document doc ) {
        final NodeList nl1 = doc.getElementsByTagName( "distance" );
        final Node node1 = nl1.item( 0 );
        final NodeList nl2 = node1.getChildNodes();
        final Node node2 = nl2.item( this.getNodeIndex( nl2, "value" ) );
        Log.i( "DistanceValue", node2.getTextContent() );
        return Integer.parseInt( node2.getTextContent() );
    }

    public Document getDocument( LatLng start, LatLng end, String mode ) {
        final String url = "http://maps.googleapis.com/maps/api/directions/xml?"
                + "origin=" + start.latitude + "," + start.longitude
                + "&destination=" + end.latitude + "," + end.longitude
                + "&sensor=false&units=metric&mode=driving";

        try {
            final HttpClient httpClient = new DefaultHttpClient();
            final HttpContext localContext = new BasicHttpContext();
            final HttpPost httpPost = new HttpPost( url );
            final HttpResponse response = httpClient.execute( httpPost, localContext );
            final InputStream in = response.getEntity().getContent();
            final DocumentBuilder builder = DocumentBuilderFactory.newInstance()
                    .newDocumentBuilder();
            final Document doc = builder.parse( in );
            return doc;
        } catch ( final Exception e ) {
            e.printStackTrace();
        }
        return null;
    }

    public String getDurationText( Document doc ) {
        final NodeList nl1 = doc.getElementsByTagName( "duration" );
        final Node node1 = nl1.item( 0 );
        final NodeList nl2 = node1.getChildNodes();
        final Node node2 = nl2.item( this.getNodeIndex( nl2, "text" ) );
        Log.i( "DurationText", node2.getTextContent() );
        return node2.getTextContent();
    }

    public int getDurationValue( Document doc ) {
        final NodeList nl1 = doc.getElementsByTagName( "duration" );
        final Node node1 = nl1.item( 0 );
        final NodeList nl2 = node1.getChildNodes();
        final Node node2 = nl2.item( this.getNodeIndex( nl2, "value" ) );
        Log.i( "DurationValue", node2.getTextContent() );
        return Integer.parseInt( node2.getTextContent() );
    }

    public String getEndAddress( Document doc ) {
        final NodeList nl1 = doc.getElementsByTagName( "end_address" );
        final Node node1 = nl1.item( 0 );
        Log.i( "StartAddress", node1.getTextContent() );
        return node1.getTextContent();
    }

    public String getStartAddress( Document doc ) {
        final NodeList nl1 = doc.getElementsByTagName( "start_address" );
        final Node node1 = nl1.item( 0 );
        Log.i( "StartAddress", node1.getTextContent() );
        return node1.getTextContent();
    }
}
